/*
 Copyright 2014-Present Algorithms in Motion LLC
 
 This file is part of jScience.
 
 jScience is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 jScience is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with jScience.  If not, see <http://www.gnu.org/licenses/>.
*/
// CREATED    : 3/12/2015
// LAST UPDATE: 3/13/2015

#include "ROC.hpp"        // ROC_pt

// STL
#include <limits>         // std::numeric_limits<>
#include <vector>         // std::vector<>


//========================================================================
//========================================================================
//
// NAME: double opt_cutoff_maxSumSeSp( const std::vector<ROC_pt> &ROC )
//
// DESC: Finds the optimal cutoff point that maximizes the sum of sensitivity and specificity; formally equivalent to minimizing the sum of false negative and false positive misclassification likelihoods.
//
// NOTES:
//     - This is equivalent to finding the operating point where the cost matrix has a slope of 1
//
//========================================================================
//========================================================================
double statsxx::ROC::opt_cutoff_maxSumSeSp( const std::vector<ROC_pt> &ROC )
{
    // default to the most conservative cutoff
    double cutoff = 1.0;
    
    double maxSumSeSp = std::numeric_limits<double>::lowest();
    
    for( auto &pt : ROC )
    {
        double SumSeSp = pt.TPR + (1.0 - pt.FPR);
        
        // assuming that the ROC points are stored in increasing order of FPR, this errs on the conservative side
        if( SumSeSp > maxSumSeSp )
        {
            cutoff = pt.score;
            
            maxSumSeSp = SumSeSp;
        }
    }
    
    return cutoff;
}




